package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.AliPayFeign;
import cn.wolfcode.feign.IntegralFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.mq.OrderMessage;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * Created by wolfcode-lanxw
 */
@Service
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private AliPayFeign aliPayFeign;
    @Autowired
    private IntegralFeignApi integralFeignApi;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;
    @Value("${pay.returnUrl}")
    private String returnUrl;

    @Override
    public String doSeckill(int time, Long seckillId, Long phone) {
        //减少真实库存
        int count = seckillProductMapper.decrStock(seckillId);
        //返回影响行数然后进行判断是否已经售空
        if (count == 0) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        String info = orderInfo(time, seckillId, phone);
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(time + ""),
                phone + ":" + seckillId);
        return info;
    }

    @Override
    public void coverStock(OrderMQResult orderMQResult) {
        //回补真实库存
        seckillProductMapper.incrStock(orderMQResult.getSeckillId());
        //回补与库存
        seckillProductService.replenishmentOfInventory(orderMQResult.getTime(), orderMQResult.getSeckillId());
        //修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, orderMQResult.getSeckillId());
        //修改订单状态
        orderInfoMapper.updateCancelStatus(orderMQResult.getOrderNo(), OrderInfo.STATUS_TIMEOUT);
    }

    @Override
    public OrderInfo getByOrderNo(String orderNo) {
        Object order = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo);
        if (StringUtils.isEmpty(order + "")) {
            return null;
        }
        return JSON.parseObject(order + "", OrderInfo.class);
    }

    @Override
    public String payOnline(String orderNo, int type) {
        OrderInfo orderInfo = getByOrderNo(orderNo);
        //调用远程支付接口
        PayVo payVo = new PayVo();
        payVo.setOutTradeNo(orderNo);
        payVo.setTotalAmount(orderInfo.getSeckillPrice() + "");
        payVo.setBody(orderInfo.getProductName());
        payVo.setSubject(orderInfo.getProductName());
        payVo.setNotifyUrl(notifyUrl);
        payVo.setReturnUrl(returnUrl);
        Result<String> result = aliPayFeign.payOnline(payVo);
        //result.getData是我们从支付宝想要获取的form表单数据
        if (result != null && !result.hasError()) {
            return result.getData();
        }
        return null;
    }

    @Override
    public void paySuccess(Map<String, String> params) {
        //插入流水
        PayLog payLog = new PayLog();
        OrderInfo orderInfo = getByOrderNo(params.get("out_trade_no"));
        payLog.setPayType(orderInfo.getPayType());
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        payLog.setNotifyTime(time);
        payLog.setOutTradeNo(params.get("trade_no"));
        payLog.setTotalAmount(orderInfo.getSeckillPrice().toString());
        payLog.setTradeNo(orderInfo.getOrderNo());
        payLogMapper.insert(payLog);
        //修改订单状态
        orderInfoMapper.changePayStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_ONLINE);
    }

    @Override
    public void refundOnline(String orderNo) {
        //退款消息的插入
        OrderInfo orderInfo = getByOrderNo(orderNo);
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderNo);
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundReason("七天无理由");
        refundLog.setRefundTime(new Date());
        refundLog.setRefundType(orderInfo.getPayType());
        refundLogMapper.insert(refundLog);
        //远程调用退款服务
        RefundVo refundVo = new RefundVo();
        refundVo.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundVo.setOutTradeNo(orderNo);
        refundVo.setRefundReason("七天无理由");
        Result<Boolean> result = aliPayFeign.refundOnline(refundVo);
        //判断是否退款成功
        if (result != null && !result.hasError()) {
            if (!result.getData()) {
                throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
            }
        }
        //修改订单状态
        int count = orderInfoMapper.changeRefundStatus(orderNo, OrderInfo.STATUS_REFUND);
        if (count == 0) {
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }
        //回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //回补与库存
        seckillProductService.replenishmentOfInventory(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }

    @Override
    public void payIntegral(String orderNo, int type) {
        //插流水
        PayLog payLog = new PayLog();
        OrderInfo orderInfo = getByOrderNo(orderNo);
        payLog.setPayType(type);
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        payLog.setNotifyTime(time);
        payLog.setTotalAmount(orderInfo.getSeckillPrice().toString());
        payLog.setTradeNo(orderNo);
        payLogMapper.insert(payLog);
        //调用远程积分服务
        OperateIntergralVo op = new OperateIntergralVo();
        op.setInfo(orderInfo.getProductName());
        op.setPk(orderNo);
        op.setUserId(orderInfo.getUserId());
        op.setValue(orderInfo.getIntergral());
        Result<String> result = integralFeignApi.reducePoints(op);
        this.result(result,SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        //修改订单状态
        orderInfoMapper.changePayStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_INTERGRAL);


    }
    public void result(Result<String> result,CodeMsg codeMsg){
        if(result!=null){
            if (result.hasError()){
                codeMsg.setCode(result.getCode());
                codeMsg.setMsg(result.getMsg());
                throw new BusinessException(codeMsg);
            }
        }else {
            throw new BusinessException(codeMsg);
        }
    }

    @Override
    public void refundIntegral(String orderNo) {
        //退款信息插入
        OrderInfo orderInfo = getByOrderNo(orderNo);
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderNo);
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundReason("七天无理由");
        refundLog.setRefundTime(new Date());
        refundLog.setRefundType(orderInfo.getPayType());
        refundLogMapper.insert(refundLog);
        OperateIntergralVo op = new OperateIntergralVo();
        op.setInfo(orderInfo.getProductName());
        op.setPk(orderNo);
        op.setUserId(orderInfo.getUserId());
        op.setValue(orderInfo.getIntergral());
        //远程调用积分退款服务
        Result<String> result = integralFeignApi.refundIntergal(op);
        result(result,SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        //修改订单状态
        int count = orderInfoMapper.changeRefundStatus(orderNo, OrderInfo.STATUS_REFUND);
        if (count == 0) {
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }
        //回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //回补与库存
        seckillProductService.replenishmentOfInventory(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }

    private String orderInfo(int time, Long seckillId, Long phone) {
        OrderInfo orderInfo = new OrderInfo();
        SeckillProductVo seckillProductVo = seckillProductService.queryById(time, seckillId);
        orderInfo.setCreateDate(new Date());//订单创建时间
        orderInfo.setDeliveryAddrId(1L);//收货地址id
        orderInfo.setProductCount(1);//购买的商品数量
        orderInfo.setProductId(seckillProductVo.getProductId());//商品id
        orderInfo.setProductImg(seckillProductVo.getProductImg());//商品图片
        orderInfo.setProductName(seckillProductVo.getProductName());//商品名称
        orderInfo.setProductPrice(seckillProductVo.getProductPrice());//商品原价
        orderInfo.setSeckillPrice(seckillProductVo.getSeckillPrice());//商品秒杀价格
        orderInfo.setUserId(phone);//用户
        orderInfo.setOrderNo(IdGenerateUtil.get().nextId() + "");//订单编号，使用推特雪花算法生成订单号
        orderInfo.setSeckillDate(seckillProductVo.getStartDate());
        orderInfo.setSeckillTime(seckillProductVo.getTime());
        orderInfo.setSeckillId(seckillProductVo.getId());
        orderInfo.setIntergral(seckillProductVo.getIntergral());
        orderInfoMapper.insert(orderInfo);
        return orderInfo.getOrderNo();
    }
}
